#include "GQuad.h"
#include "GMath.h"

namespace GMath
{
	GQuad::GQuad()
	{
		Create(GVector3::Zero, GVector3::Zero, GVector3::Zero, GVector3::Zero);
	}

	GQuad::GQuad(const GVector3& P0, const GVector3& P1, const GVector3& P2, const GVector3& P3)
	{
		Create(P0, P1, P2, P3);
	}

	void GQuad::Create(const GVector3& P0, const GVector3& P1, const GVector3& P2, const GVector3& P3)
	{
		Point0 = P0;
		Point1 = P1;
		Point2 = P2;
		Point3 = P3;
	}

	float GQuad::GetArea() const
	{
		GTriangle3 Triangle1(Point0, Point1, Point2);
		GTriangle3 Triangle2(Point2, Point3, Point0);
		
		return Triangle1.GetArea() + Triangle2.GetArea();
	}

	GVector3 GQuad::GetCenter() const
	{
		return (Point0 + Point1 + Point2 + Point3) * 0.25f;
	}

	GVector3 GQuad::GetNormal() const
	{
		GTriangle3 Temp(Point0, Point1, Point2);
		return Temp.GetNormal();
	}
	
	bool GQuad::CheckFront(const GVector3& ViewVec, bool TwoSided) const
	{
		GTriangle3 Triangle(Point0, Point1, Point2);
		return Triangle.CheckFront(ViewVec, TwoSided);
	}

	bool GQuad::CheckPlanar() const
	{
		GVector3 Vec1 = Point1 - Point0;
		GVector3 Vec2 = Point2 - Point0;

		GVector3 CrossVec;
		GVector3::Cross(CrossVec, Vec1, Vec2);

		float Result = GVector3::Dot(CrossVec, Point3 - Point2);

		return EqualF(Result, 0.0f);
	}

	bool GQuad::CheckConvex() const
	{
		//! test this method
		float DotResult = 0;

		GVector3 Vec0 = Point3 - Point2;
		GVector3 Vec1 = Point2 - Point1;
		GVector3 Vec2 = Point1 - Point0;
		GVector3 Vec3 = Point0 - Point3;

		// Corner 0
		GVector3 Cross0;
		GVector3::Cross(Cross0, -Vec3, Vec2);

		// Corner 1
		GVector3 Cross1;
		GVector3::Cross(Cross1, -Vec2, Vec1);
		DotResult = GVector3::Dot(Cross0, Cross1);
		if (DotResult < 0)
		{
			return false;
		}

		// Corner 2
		GVector3 Cross2;
		GVector3::Cross(Cross2, -Vec1, Vec0);
		DotResult = GVector3::Dot(Cross0, Cross2);
		if (DotResult < 0)
		{
			return false;
		}

		// Corner 3
		GVector3 Cross3;
		GVector3::Cross(Cross3, Vec3, -Vec0);
		DotResult = GVector3::Dot(Cross0, Cross3);
		if (DotResult < 0)
		{
			return false;
		}

		return true;
	}

	void GQuad::Convert(OUTPUT GPlane& Output, const GQuad& Quad)
	{
		Output.Create(Quad.Point0, Quad.Point1, Quad.Point2);
	}

	void GQuad::Convert(OUTPUT GTriangle3& Output1, OUTPUT GTriangle3& Output2, const GQuad& Quad)
	{
		Output1.Create(Quad.Point0, Quad.Point1, Quad.Point2);
		Output2.Create(Quad.Point2, Quad.Point3, Quad.Point0);
	}
	
	const GQuad& GQuad::operator = (const GQuad& Other)
	{
		Point0 = Other.Point0;
		Point1 = Other.Point1;
		Point2 = Other.Point2;
		Point3 = Other.Point3;
		return *this;
	}
}